<?php

namespace app\wechat\service;

use app\admin\service\BaseService;
use app\wechat\model\ApplicationModel;
use app\wechat\model\MiniUserModel;
use app\wechat\model\WxpayOrderModel;
use EasyWeChat\Factory;
use Exception;
use think\facade\Db;

/**
 * 微信支付类
 *
 * @Author tanruizheng
 * @DateTime 2021-08-17
 */
class WxpayService extends BaseService
{
    public $payment;
    protected $appId;

    /**
     * 微信支付实例
     *
     * @Author tanruizheng
     * @DateTime 2021-08-10
     * @return object
     */
    public function getPayment(){
        return $this->payment;
    }

    public function __construct($appId)
    {
        $application = ApplicationModel::where(
            [
                'app_id'        => $appId,
            ]
        )->findOrEmpty()->toArray();
        if(empty($application)){
           throw new Exception('应用信息不存在');
        }
        $certDir = runtime_path() . 'wechat/cert/'.$appId.'/';
        $certPath = $certDir.'cert.pem';
        $keyPath =  $certDir.'key.pem';
        if(!is_dir($certDir)){
            mkdir($certDir, 0755, true);
        }
        if(!file_exists($certPath)){
            file_put_contents($certPath, $application['cert_path']);
        }
        if(!file_exists($keyPath)){
            file_put_contents($certPath, $application['key_path']);
        }
        $config = [
            'app_id'        => $application['app_id'],
            'mch_id'        => $application['mch_id'],
            'key'           => $application['mch_key'],
            'cert_path'     => $certPath,
            'key_path'      => $keyPath,
            'notify_url'    => url('Index/notifyUrl',[],true,true)->__toString(),
        ];
        $this->appId = $appId;
        $this->payment = Factory::payment($config);
    }

    /**
     * 统一下单
     *
     * @Author tanruizheng
     * @DateTime 2021-08-23
     * @param [type] $openid
     * @param [type] $outTradeNo
     * @param [type] $totalFee
     * @param string $tradeType
     * @param string $body
     * @return void
     */
    public function createUnify($openid, $outTradeNo, $totalFee, $tradeType = 'JSAPI', $body = '微信支付'){
        $result = $this->payment->order->unify([
            'body' => $body,
            'out_trade_no' => $outTradeNo,
            'total_fee' => $totalFee,
            'trade_type' => $tradeType, // 支付方式
            'openid' => $openid,
        ]);
        if($result['result_code'] == 'SUCCESS' && $result['return_code'] == 'SUCCESS'){
            return self::createSuccess('success',[
                'prepay_id' => $result['prepay_id']
            ]);
        }
        return self::createFail(isset($result['return_msg']) ?$result['return_msg'] : '获取prepay_id失败');
    } 

    /**
     * 获取微信公众号支付参数
     *
     * @Author tanruizheng
     * @DateTime 2021-08-23
     * @param [type] $openid
     * @param [type] $outTradeNo
     * @param [type] $totalFee
     * @param string $body
     * @return void
     */
    public function getJssdkPayConfig($openid, $outTradeNo, $totalFee, $body = '微信支付'){
        $unifyRes= $this->createUnify($openid, $outTradeNo, $totalFee, 'JSAPI', $body);
        if(!$unifyRes['status']){
            return self::createFail('微信支付失败:' . $unifyRes['msg']);
        }
        $wxpayOrder = new WxpayOrderModel();
        $wxpayOrder->app_id = $this->appId;
        $wxpayOrder->open_id = $openid;
        $wxpayOrder->out_trade_no = $outTradeNo;
        $wxpayOrder->total_fee = $totalFee;
        $wxpayOrder->save();
        $res = $this->payment->jssdk->sdkConfig($unifyRes['prepayId'], false);
        return self::createSuccess('success',$res);
    }

    /**
     * 获取微信小程序支付参数
     *
     * @Author tanruizheng
     * @DateTime 2021-08-23
     * @param [type] $openid
     * @param [type] $outTradeNo
     * @param [type] $totalFee
     * @param string $body
     * @return void
     */
    public function getMiniPayConfig($openid, $outTradeNo, $totalFee, $body = '微信支付'){
        $unifyRes = $this->createUnify($openid, $outTradeNo, $totalFee, 'JSAPI', $body);
        if(!$unifyRes['status']){
            return self::createFail('微信支付失败:' . $unifyRes['msg']);
        }
        $wxpayOrder = new WxpayOrderModel();
        $wxpayOrder->app_id = $this->appId;
        $wxpayOrder->open_id = $openid;
        $wxpayOrder->out_trade_no = $outTradeNo;
        $wxpayOrder->total_fee = $totalFee;
        $wxpayOrder->save();
        $res = $this->payment->jssdk->bridgeConfig($unifyRes['prepayId'], false);
        return self::createSuccess('success',$res);
    }

    /**
     * 支付回调处理
     *
     * @Author tanruizheng
     * @DateTime 2021-08-23
     * @param [type] $func
     * @return object
     */
    public function handlePayNotify($func){
        return $this->getPayment()->handlePaidNotify(function($message, $fail) use($func){
            $wxpayOrder = WxpayOrderModel::where('out_trade_no', $message['out_trade_no'])->findOrEmpty();
            if(!$wxpayOrder->isEmpty()){
                $wxpayOrder->mch_id = isset($message['mch_id']) ? $message['mch_id'] : '';
                $wxpayOrder->nonce_str = isset($message['nonce_str']) ? $message['nonce_str'] : '';
                $wxpayOrder->sign = isset($message['sign']) ? $message['sign'] : '';
                $wxpayOrder->result_code = isset($message['result_code']) ? $message['result_code'] : '';
                $wxpayOrder->err_code = isset($message['err_code']) ? $message['err_code'] : '';
                $wxpayOrder->err_code_des = isset($message['err_code_des']) ? $message['err_code_des'] : '';
                $wxpayOrder->open_id = isset($message['openid']) ? $message['openid'] : '';
                $wxpayOrder->is_subscribe = isset($message['is_subscribe']) ? $message['is_subscribe'] : '';
                $wxpayOrder->trade_type = isset($message['trade_type']) ? $message['trade_type'] : '';
                $wxpayOrder->bank_type = isset($message['bank_type']) ? $message['bank_type'] : '';
                $wxpayOrder->total_fee = isset($message['total_fee']) ? $message['total_fee'] : '';
                $wxpayOrder->cash_fee = isset($message['cash_fee']) ? $message['cash_fee'] : '';
                $wxpayOrder->transaction_id = isset($message['transaction_id']) ? $message['transaction_id'] : '';
                $wxpayOrder->out_trade_no = isset($message['out_trade_no']) ? $message['out_trade_no'] : '';
                $wxpayOrder->time_end = isset($message['time_end']) ? $message['time_end'] : '';
                $wxpayOrder->save();
                $func($message, $fail);
            }else{
                $fail('订单不存在');
            }
        });
    }

    /**
     * 企业付款到用户零钱
     *
     * @Author tanruizheng
     * @DateTime 2021-08-23
     * @param [type] $partnerTradeNo
     * @param [type] $openid
     * @param [type] $amount
     * @param string $desc
     * @param string $checkName
     * @param string $reUserName
     * @return void
     */
    public function toBalance($partnerTradeNo, $openid, $amount, $desc = '企业付款', $checkName = ' NO_CHECK', $reUserName = ''){
        try {
            $result = $this->getPayment()->transfer->toBalance([
                'partner_trade_no' => $partnerTradeNo, // 商户订单号，需保持唯一性(只能是字母或者数字，不能包含有符号)
                'openid' => $openid,
                'check_name' => $checkName, // NO_CHECK：不校验真实姓名, FORCE_CHECK：强校验真实姓名
                're_user_name' => $reUserName, // 如果 check_name 设置为FORCE_CHECK，则必填用户真实姓名
                'amount' => $amount * 100, // 企业付款金额，单位为分
                'desc' => $desc, // 企业付款操作说明信息。必填
            ]);
            if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
                return self::createSuccess('success',$result);
            }else{
                return self::createFail('fail',$result);
            }
        } catch (\EasyWeChat\Kernel\Exceptions\Exception $e) {
            return self::createFail($e->getMessage());
        }
    }

    /**
     * 发送普通红包接口
     *
     * @Author tanruizheng
     * @DateTime 2021-08-23
     * @param [type] $mchBillno
     * @param [type] $sendName
     * @param [type] $reOpenid
     * @param [type] $totalNum
     * @param [type] $totalAmount
     * @param string $wishing
     * @param string $clientIp
     * @param string $actName
     * @param string $remark
     * @return void
     */
    public function sendNormal(
                        $mchBillno, 
                        $sendName,
                        $reOpenid,
                        $totalNum,
                        $totalAmount, 
                        $wishing = '祝福语', 
                        $clientIp = '', 
                        $actName = '', 
                        $remark = '备注'){
        try {
            $redpackData = [
                'mch_billno'   => $mchBillno,
                'send_name'    => $sendName,
                're_openid'    => $reOpenid,
                'total_num'    => $totalNum,  //固定为1，可不传
                'total_amount' => $totalAmount,  //单位为分，不小于100
                'wishing'      => $wishing,
                'client_ip'    => $clientIp,  //可不传，不传则由 SDK 取当前客户端 IP
                'act_name'     => $actName,
                'remark'       => $remark,
            ];
            
            $result = $this->getPayment()->redpack->sendNormal($redpackData);
            if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
                return self::createSuccess('success',$result);
            }else{
                return self::createFail('fail',$result);
            }
        } catch (\EasyWeChat\Kernel\Exceptions\Exception $e) {
            return self::createFail($e->getMessage());
        }
    }

    /**
     * 根据商户订单号退款

     *
     * @Author tanruizheng
     * @DateTime 2021-08-23
     * @param [type] $number
     * @param [type] $refundNumber
     * @param [type] $totalFee
     * @param [type] $refundFee
     * @param array $config
     * @return void
     */
    public function refundByOutTradeNumber(
                        $number, 
                        $refundNumber,
                        $totalFee,
                        $refundFee,
                        $config = []){
        try {
           // 参数分别为：商户订单号、商户退款单号、订单金额、退款金额、其他参数
           $result = $this->getPayment()->refund->byOutTradeNumber($number, $refundNumber, $totalFee, $refundFee, $config = []);
            if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
                return self::createSuccess('success',$result);
            }else{
                return self::createFail('fail',$result);
            }
        } catch (\EasyWeChat\Kernel\Exceptions\Exception $e) {
            return self::createFail($e->getMessage());
        }
    }
}